package utils

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-contrib/multitemplate"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"path/filepath"
	"reflect"
	"strings"
	"vueBasic/app/admin/filter"
	"vueBasic/extend/conv"
	"vueBasic/extend/valid"
)

// 获取客户端ip
func GetClientIP(c *gin.Context) string {
	ClientIP := c.ClientIP()
	RemoteIP := c.RemoteIP()
	ip := c.Request.Header.Get("X-Forwarded-For")
	if strings.Contains(ip, "127.0.0.1") || ip == "" {
		ip = c.Request.Header.Get("X-real-ip")
	}
	if ip == "" {
		ip = "127.0.0.1"
	}
	if RemoteIP != "127.0.0.1" {
		ip = RemoteIP
	}
	if ClientIP != "127.0.0.1" {
		ip = ClientIP
	}
	return ip
}

// 从协程上下文中解析出token
func GetClaims(name string, c *gin.Context) interface{} {
	data, exits := c.Get("claims")
	if exits {
		return data.(jwt.MapClaims)[name]
	}
	return nil
}

// 从协程上下文中解析出token
func GetApiClaims(name string, c *gin.Context) interface{} {
	data, exits := c.Get("user")
	if exits {
		return data.(jwt.MapClaims)[name]
	}
	return nil
}

// 绑定并且验证
func BindAndValid(c *gin.Context, form interface{}) error {
	if err := c.ShouldBind(form); err != nil {
		return errors.New("参数格式错误:" + err.Error())
	}
	if reflect.TypeOf(form).Kind() == reflect.Ptr && reflect.ValueOf(form).Elem().Kind() == reflect.Struct {
		if err := valid.Validate.Struct(form); err != nil {
			for _, error := range err.(validator.ValidationErrors) {
				return errors.New(error.Translate(valid.Trans))
			}
		}
	}
	return nil
}

// 自定义多模板路径
func LoadTemplates(templatesDir string) multitemplate.Renderer {
	r := multitemplate.NewRenderer()
	layouts, err := filepath.Glob(templatesDir + "/layouts/*.html")
	if err != nil {
		panic(err.Error())
	}
	templates, err := filepath.Glob(templatesDir + "/admin/**/*.html")
	if err != nil {
		panic(err.Error())
	}
	for _, template := range templates {
		fmt.Println(template)
		if strings.Contains(template, "login.html") || strings.Contains(template, "index\\index.html") {
			layoutCopy := make([]string, 0)
			files := append(layoutCopy, template)
			r.AddFromFiles(filepath.Base(template), files...)
		} else {
			layoutCopy := make([]string, len(layouts))
			copy(layoutCopy, layouts)
			files := append(layoutCopy, template)
			r.AddFromFiles(filepath.Base(template), files...)
		}
	}
	return r
}

// 递归回去函数  TODO:需要优化
func GetTreeRecursive(list []*filter.AccessNode, parentId int, modelType int) []*filter.AccessNode {
	res := make([]*filter.AccessNode, 0)
	for _, v := range list {
		if v.ModuleId == parentId {
			v.Children = GetTreeRecursive(list, conv.Int(v.Id), modelType)
			if v.Icon == "" && modelType == 0 {
				v.Icon = "el-icon-menu"
			}
			res = append(res, v)
		}
	}
	return res
}

// 设置session
func SetSession(key string, val interface{}, c *gin.Context) {
	session := sessions.Default(c)
	session.Set(key, val)
	session.Save()
}

// 获取session
func GetSession(key string, c *gin.Context) any {
	session := sessions.Default(c)
	return session.Get(key)
}

// 删除session
func DelSession(key string, c *gin.Context) {
	session := sessions.Default(c)
	session.Delete(key)
	session.Save()
}

// 检查上传文件格式是否合法
func FileValid(fileExt string, typeString string) bool {
	ext := strings.Replace(fileExt, ".", "", -1)
	allowExt := conv.StringToSlice(strings.ToLower(typeString), ",")
	var valid = false
	if conv.IsValueInList(strings.ToLower(ext), allowExt) {
		valid = true
	}
	return valid
}

// MD5加密
func Md5(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum(nil))
}
